#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@file: contacts.py
@time: 2024-06-21 20:41
@desc: 
"""
import traceback
from io import BytesIO
from flask import request, jsonify, Blueprint, send_file
from project_model import Contact, Image
from tools import log_operations, token_required
from global_scope import get_db, contacts_sheet_name, images_sheet_name, MAX_PAGE_SIZE
import pandas as pd
from tools import get_contacts_df, get_images_df
from tools import excel_to_contacts, excel_to_images
from common_tools import to_dict, apply_formatting

db = get_db()

contact_bp = Blueprint("contacts", __name__, url_prefix='/contacts')


@contact_bp.route('', methods=['POST'])
@log_operations
@token_required
def add_contact():
    data = request.json
    name = data.get('name')
    phone = data.get('phone')
    address = data.get('address')
    qq = data.get('qq')
    email = data.get('email')
    remark = data.get('remark')
    image_urls = data.get('images', [])

    if not name or not phone:
        return jsonify({"code": 1, "message": "Username and phone are required"}), 400

    new_contact = Contact.query.filter_by(name=name, phone=phone).first()
    if not new_contact:
        new_contact = Contact(name=name, phone=phone, address=address, qq=qq, email=email, remark=remark)

    for url in image_urls:
        image = Image.query.filter_by(imageUrl=url).first()
        if image is None:
            image = Image(image_url=url)
        new_contact.images.append(image)

    db.session.add(new_contact)
    db.session.commit()

    return jsonify({"code": 0, "message": "Contact added successfully", "data": new_contact.id}), 201


@contact_bp.route('/<int:contact_id>', methods=['GET'])
@log_operations
@token_required
def get_contact(contact_id):
    contact = db.session.get(Contact, contact_id)
    if not contact:
        return jsonify({"code": 1, "message": "Contact not found"}), 404

    contact_data = {
        "id": contact.id,
        "name": contact.name,
        "phone": contact.phone,
        "address": contact.address,
        "qq": contact.qq,
        "email": contact.email,
        "remark": contact.remark,
        "create_time": contact.createTime.isoformat(),
        "update_time": contact.updateTime.isoformat(),
        "images": [img.imageUrl for img in contact.images]
    }

    return jsonify({"code": 0, "message": "OK", "data": contact_data}), 200


@contact_bp.route('', methods=['GET'])
@log_operations
@token_required
def list_contacts():
    name = request.args.get('name')
    phone = request.args.get('phone')
    address = request.args.get('address')
    remark = request.args.get('remark')
    page_no = request.args.get('pageNo', default=1, type=int)
    page_size = request.args.get('pageSize', default=MAX_PAGE_SIZE, type=int)

    query = Contact.query

    if name:
        query = query.filter(Contact.name.contains(name))
    if phone:
        query = query.filter(Contact.phone.contains(phone))
    if address:
        query = query.filter(Contact.address.contains(address))
    if remark:
        query = query.filter(Contact.remark.contains(remark))

    total_count = query.count()
    contacts = query.offset((page_no - 1) * page_size).limit(page_size).all()

    contact_list = [
        {
            "id": contact.id,
            "name": contact.name,
            "phone": contact.phone,
            "address": contact.address,
            "qq": contact.qq,
            "email": contact.email,
            "remark": contact.remark,
            "createTime": contact.createTime.isoformat(),
            "updateTime": contact.updateTime.isoformat(),
            "value": f"{contact.name} | {contact.phone}",
            "images": [{"id": img.id, "imageUrl": img.imageUrl} for img in contact.images]
        }
        for contact in contacts
    ]

    return jsonify({
        "code": 0,
        "message": "OK",
        "data": {
            "pageData": contact_list,
            "total": total_count,
            "pageNo": page_no,
            "pageSize": page_size
        }
    }), 200


@contact_bp.route('/<int:contact_id>', methods=['PATCH'])
@log_operations
@token_required
def update_contact(contact_id):
    data = request.json
    contact = db.session.get(Contact, contact_id)
    if not contact:
        return jsonify({"code": 1, "message": "Contact not found"}), 404

    if 'name' in data:
        contact.name = data['name']
    if 'phone' in data:
        contact.phone = data['phone']
    if 'address' in data:
        contact.address = data['address']
    if 'qq' in data:
        contact.qq = data['qq']
    if 'email' in data:
        contact.email = data['email']
    if 'remark' in data:
        contact.remark = data['remark']
    if 'images' in data:
        contact.images.clear()
        for img_dict in data['images']:
            url = img_dict.get('imageUrl')
            if url and isinstance(url, str) and url.startswith('http'):
                image = Image.query.filter_by(imageUrl=url).first()
                if image is None:
                    image = Image(image_url=url)
                contact.images.append(image)

    db.session.commit()

    return jsonify({"code": 0, "message": "Contact updated successfully"}), 200


@contact_bp.route('/<int:contact_id>', methods=['DELETE'])
@log_operations
@token_required
def delete_contact(contact_id):
    contact = db.session.get(Contact, contact_id)
    if not contact:
        return jsonify({"code": 1, "message": "Contact not found"}), 404

    db.session.delete(contact)
    db.session.commit()

    return jsonify({"code": 0, "message": "Contact deleted successfully"}), 200


@contact_bp.route('/upload', methods=['POST'])
@log_operations
@token_required
def upload_contacts():
    if 'file' not in request.files:
        return jsonify({"code": 1, "message": "No file part"}), 400

    file = request.files['file']
    if file.filename == '':
        return jsonify({"code": 1, "message": "No selected file"}), 400

    try:
        excel_to_images(file, request)
        new_contacts, updated_contacts = excel_to_contacts(file, request)
        return jsonify({
            "code": 0,
            "message": f"Contacts uploaded successfully: {new_contacts} added, {updated_contacts} updated"
        }), 201
    except Exception as e:
        tb = traceback.format_exc()
        request.trace_logger.error(f"Exception occurred: {str(e)}\n{tb}")
        return jsonify({"code": 1, "message": str(e)}), 500


@contact_bp.route('/download', methods=['GET'])
@log_operations
@token_required
def download_contacts():
    df = get_contacts_df()
    output = BytesIO()
    with pd.ExcelWriter(output, engine='openpyxl') as writer:
        df.to_excel(writer, index=False, sheet_name=contacts_sheet_name)
        df_images = get_images_df()
        df_images.to_excel(writer, index=False, sheet_name=images_sheet_name)

        apply_formatting(writer.sheets[contacts_sheet_name], df)
        apply_formatting(writer.sheets[images_sheet_name], df_images)
    output.seek(0)

    return send_file(output, download_name="Contacts.xlsx", as_attachment=True)
